#include "Drawing.h"


void Drawing::drawCube(vector3<float> center, float side){
    register float x = center.x;
    register float y = center.y;
    register float z = center.z;
    glPushMatrix();

    glBegin(GL_QUADS);

    glNormal3f(0,1,0);
    glVertex3f( side+x, side+y,-side+z);          // Top Right Of The Quad (Top)
    glVertex3f(-side+x, side+y,-side+z);          // Top Left Of The Quad (Top)
    glVertex3f(-side+x, side+y, side+z);          // Bottom Left Of The Quad (Top)
    glVertex3f( side+x, side+y, side+z);

    glNormal3f(0,-1,0);
    glVertex3f( side+x,-side+y, side+z);          // Top Right Of The Quad (Bottom)
    glVertex3f(-side+x,-side+y, side+z);          // Top Left Of The Quad (Bottom)
    glVertex3f(-side+x,-side+y,-side+z);          // Bottom Left Of The Quad (Bottom)
    glVertex3f( side+x,-side+y,-side+z);

    glNormal3f(0,0,1);
    glVertex3f( side+x, side+y, side+z);          // Top Right Of The Quad (Front)
    glVertex3f(-side+x, side+y, side+z);          // Top Left Of The Quad (Front)
    glVertex3f(-side+x,-side+y, side+z);          // Bottom Left Of The Quad (Front)
    glVertex3f( side+x,-side+y, side+z);

    glNormal3f(0,0,-1);
    glVertex3f( side+x,-side+y,-side+z);          // Bottom Left Of The Quad (Back)
    glVertex3f(-side+x,-side+y,-side+z);          // Bottom Right Of The Quad (Back)
    glVertex3f(-side+x, side+y,-side+z);          // Top Right Of The Quad (Back)
    glVertex3f( side+x, side+y,-side+z);

    glNormal3f(-1,0,0);
    glVertex3f(-side+x, side+y, side+z);          // Top Right Of The Quad (Left)
    glVertex3f(-side+x, side+y,-side+z);          // Top Left Of The Quad (Left)
    glVertex3f(-side+x,-side+y,-side+z);          // Bottom Left Of The Quad (Left)
    glVertex3f(-side+x,-side+y, side+z);


    glNormal3f(1,0,0);
    glVertex3f( side+x, side+y,-side+z);          // Top Right Of The Quad (Right)
    glVertex3f( side+x, side+y, side+z);          // Top Left Of The Quad (Right)
    glVertex3f( side+x,-side+y, side+z);          // Bottom Left Of The Quad (Right)
    glVertex3f( side+x,-side+y,-side+z);

    glEnd();

    glPopMatrix();
}

void Drawing::drawCuboid(vector3<float> start, vector3<float> end){
    glPushMatrix();

    glBegin(GL_QUADS);

    //TOP
    glNormal3f(0,1,0);
    glVertex3f(start.x, end.y, start.z);
    glVertex3f(start.x, end.y, end.z);
    glVertex3f(end.x, end.y, end.z);
    glVertex3f(end.x, end.y, start.z);

    //BOTTOM
    glNormal3f(0,-1,0);
    glVertex3f(start.x, start.y, start.z);
    glVertex3f(end.x, start.y, start.z);
    glVertex3f(end.x, start.y, end.z);
    glVertex3f(start.x, start.y, end.z);

    //FRONT
    glNormal3f(0,0,1);
    glVertex3f(end.x, end.y, end.z);
    glVertex3f(start.x, end.y, end.z);
    glVertex3f(start.x, start.y, end.z);
    glVertex3f(end.x, start.y, end.z);

    //BACK
    glNormal3f(0,0,-1);
    glVertex3f(end.x, end.y, start.z);
    glVertex3f(end.x, start.y, start.z);
    glVertex3f(start.x, start.y, start.z);
    glVertex3f(start.x, end.y, start.z);

    //LEFT
    glNormal3f(-1,0,0);
    glVertex3f(start.x, start.y, start.z);
    glVertex3f(start.x, start.y, end.z);
    glVertex3f(start.x, end.y, end.z);
    glVertex3f(start.x, end.y, start.z);

    //RIGHT
    glNormal3f(1,0,0);
    glVertex3f(end.x, start.y, start.z);
    glVertex3f(end.x, end.y, start.z);
    glVertex3f(end.x, end.y, end.z);
    glVertex3f(end.x, start.y, end.z);

    glEnd();

    glPopMatrix();
}

void Drawing::drawWireVoxel(int x, int y, int z){
    static GLuint displayID=0;
    glPushMatrix();
    glTranslatef(x,y,z);

    if(!displayID){
        displayID=glGenLists(1);
        glNewList(displayID,GL_COMPILE_AND_EXECUTE);
        glLineWidth(3);
        glColor3f(1,0,0);
        glBegin(GL_LINES);
        glVertex3f(0,0,0); glVertex3f(1,0,0);
        glVertex3f(1,0,0); glVertex3f(1,0,1);
        glVertex3f(1,0,1); glVertex3f(0,0,1);
        glVertex3f(0,0,1); glVertex3f(0,0,0);

        glVertex3f(0,0,0);glVertex3f(0,1,0);
        glVertex3f(1,0,0);glVertex3f(1,1,0);
        glVertex3f(1,0,1);glVertex3f(1,1,1);
        glVertex3f(0,0,1);glVertex3f(0,1,1);

        glVertex3f(0,1,0); glVertex3f(1,1,0);
        glVertex3f(1,1,0); glVertex3f(1,1,1);
        glVertex3f(1,1,1); glVertex3f(0,1,1);
        glVertex3f(0,1,1); glVertex3f(0,1,0);
        glEnd();
        glEndList();
    }else glCallList(displayID);

    glPopMatrix();

}

void Drawing::drawWireCuboid(vector3<int> s, vector3<int> e, float r, float g, float b, float width){

    glLineWidth(width);
    glColor3f(r,g,b);
    glBegin(GL_LINES);
    glVertex3f(s.x,s.y,s.z); glVertex3f(e.x,s.y,s.z);
    glVertex3f(e.x,s.y,s.z); glVertex3f(e.x,s.y,e.z);
    glVertex3f(e.x,s.y,e.z); glVertex3f(s.x,s.y,e.z);
    glVertex3f(s.x,s.y,e.z); glVertex3f(s.x,s.y,s.z);

    glVertex3f(s.x,s.y,s.z);glVertex3f(s.x,e.y,s.z);
    glVertex3f(e.x,s.y,s.z);glVertex3f(e.x,e.y,s.z);
    glVertex3f(e.x,s.y,e.z);glVertex3f(e.x,e.y,e.z);
    glVertex3f(s.x,s.y,e.z);glVertex3f(s.x,e.y,e.z);

    glVertex3f(s.x,e.y,s.z); glVertex3f(e.x,e.y,s.z);
    glVertex3f(e.x,e.y,s.z); glVertex3f(e.x,e.y,e.z);
    glVertex3f(e.x,e.y,e.z); glVertex3f(s.x,e.y,e.z);
    glVertex3f(s.x,e.y,e.z); glVertex3f(s.x,e.y,s.z);
    glEnd();

}

void Drawing::drawWireCuboid(vector3<float> s, vector3<float> e, float r, float g, float b, float width){

    glLineWidth(width);
    glColor3f(r,g,b);
    glBegin(GL_LINES);
    glVertex3f(s.x,s.y,s.z); glVertex3f(e.x,s.y,s.z);
    glVertex3f(e.x,s.y,s.z); glVertex3f(e.x,s.y,e.z);
    glVertex3f(e.x,s.y,e.z); glVertex3f(s.x,s.y,e.z);
    glVertex3f(s.x,s.y,e.z); glVertex3f(s.x,s.y,s.z);

    glVertex3f(s.x,s.y,s.z);glVertex3f(s.x,e.y,s.z);
    glVertex3f(e.x,s.y,s.z);glVertex3f(e.x,e.y,s.z);
    glVertex3f(e.x,s.y,e.z);glVertex3f(e.x,e.y,e.z);
    glVertex3f(s.x,s.y,e.z);glVertex3f(s.x,e.y,e.z);

    glVertex3f(s.x,e.y,s.z); glVertex3f(e.x,e.y,s.z);
    glVertex3f(e.x,e.y,s.z); glVertex3f(e.x,e.y,e.z);
    glVertex3f(e.x,e.y,e.z); glVertex3f(s.x,e.y,e.z);
    glVertex3f(s.x,e.y,e.z); glVertex3f(s.x,e.y,s.z);
    glEnd();

}

void Drawing::drawPyramid(float side, float height, float r, float g, float b, bool wireframe){
    float sideh=side/2;
    glColor3f(r,g,b);
    if(wireframe){
        glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
        glDisable(GL_CULL_FACE);
    }
    glBegin(GL_TRIANGLE_FAN);

    glVertex3f(sideh,height,sideh);

    glVertex3f(side,0,side);
    glVertex3f(side,0,0);
    glVertex3f(0,0,0);
    glVertex3f(0,0,side);
    glVertex3f(side,0,side);

    glEnd();

    glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
    glEnable(GL_CULL_FACE);
}

void Drawing::drawLine(vector3<float> start, vector3<float> end){
    glBegin(GL_LINES);
    glVertex3f(start.x, start.y, start.x);
    glVertex3f(end.x, end.y, end.x);
    glEnd();
}

void Drawing::drawLine2D(float x1, float y1, float x2, float y2){
    glLineWidth(3.0);
    glBegin(GL_LINES);
    glVertex2f(x1,y1);
    glVertex2f(x2,y2);
    glEnd();
}

void Drawing::drawBox(float x1, float y1, float x2, float y2){
    glBegin(GL_QUADS);
    glVertex2f(x1,y1);
    glVertex2f(x1,y2);
    glVertex2f(x2,y2);
    glVertex2f(x2,y1);
    glEnd();
}

void Drawing::drawBoxWithoutFill(float x1, float y1, float x2, float y2) {
    drawLine2D(x1, y1, x2, y1); //horizontal
    drawLine2D(x1,y1, x1, y2);
    drawLine2D(x1, y2, x2, y2);
    drawLine2D(x2, y1, x2, y2);

}

void Drawing::drawSphere(float r,int n, float red, float g, float b, bool wireframe){

       //int q = (int)(n/2 + 0.5);
       glColor3f(red, g,b);
       glPushMatrix();

       if(wireframe)glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
       glDisable(GL_CULL_FACE);

       glBegin(GL_QUADS);
       for(int i=0;i<n;i++)
            for(int j=0;j<2*n;j++){

                glNormal3f(sin(i*M_PI/n)*cos(j*M_PI/n),cos(i*M_PI/n)*cos(j*M_PI/n),sin(j*M_PI/n));
                glVertex3f(r*sin(i*M_PI/n)*cos(j*M_PI/n),r*cos(i*M_PI/n)*cos(j*M_PI/n),r*sin(j*M_PI/n));

                glNormal3f(sin((i+1)*M_PI/n)*cos(j*M_PI/n),cos((i+1)*M_PI/n)*cos(j*M_PI/n),sin(j*M_PI/n));
                glVertex3f(r*sin((i+1)*M_PI/n)*cos(j*M_PI/n),r*cos((i+1)*M_PI/n)*cos(j*M_PI/n),r*sin(j*M_PI/n));

                glNormal3f(sin((i+1)*M_PI/n)*cos((j+1)*M_PI/n),cos((i+1)*M_PI/n)*cos((j+1)*M_PI/n),sin((j+1)*M_PI/n));
                glVertex3f(r*sin((i+1)*M_PI/n)*cos((j+1)*M_PI/n),r*cos((i+1)*M_PI/n)*cos((j+1)*M_PI/n),r*sin((j+1)*M_PI/n));

                glNormal3f(sin(i*M_PI/n)*cos((j+1)*M_PI/n),cos(i*M_PI/n)*cos((j+1)*M_PI/n),sin((j+1)*M_PI/n));
                glVertex3f(r*sin(i*M_PI/n)*cos((j+1)*M_PI/n),r*cos(i*M_PI/n)*cos((j+1)*M_PI/n),r*sin((j+1)*M_PI/n));

            }
       glEnd();
       glEnable(GL_CULL_FACE);
       glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

       glPopMatrix();


}

void Drawing::drawOnOverlay(void (*func)()){
    beginOverlay();

    glPushMatrix();
    func();
    glPopMatrix();

    endOverlay();
}

void Drawing::beginOverlay(){
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluOrtho2D(0,GlobalStates::getInstance()->getScreenWidth(),GlobalStates::getInstance()->getScreenHeight(),0);
    //glOrtho(-10, 10, -10, 10, -10, 10);
    glMatrixMode(GL_MODELVIEW);
}

void Drawing::endOverlay(){
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
}

void Drawing::drawTriangle(float base, float height){
    float halfb= base*0.5;
    float halfh = height*0.5;
    glBegin(GL_TRIANGLES);
    glVertex2f(halfb,-halfh);
    glVertex2f(-halfb,-halfh);
    glVertex2f(0,halfh);
    glEnd();
}
